<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>二维热力图</title>
    <link rel="stylesheet" href="./lib/styles.css" />

    <script type="text/javascript" src="./lib/aircity/ac_conf.js"></script>
    <script type="text/javascript" src="./lib/aircity/ac.min.js"></script>
    <script type="text/javascript" src="./lib/Vue3.js"></script>
    <script type="text/javascript" src="./lib/ElementPlus/index.js"></script>
    <link rel="stylesheet" href="./lib/ElementPlus/index.css" />
  </head>
  <body>
    <div id="dom">
      <div id="player"></div>

      <div class="btn-list">
        <el-dropdown placement="bottom" @command="HeatMapClick">
          <div class="btn">添加二维热力图</div>
          <template #dropdown>
            <el-dropdown-menu>
              <el-dropdown-item command="normal">标准热力图</el-dropdown-item>
              <el-dropdown-item command="customColor"
                >自定义颜色热力图</el-dropdown-item
              >
              <el-dropdown-item command="customerStyle"
                >自定义样式热力图</el-dropdown-item
              >
            </el-dropdown-menu>
          </template>
        </el-dropdown>
      </div>
      <div class="slide" v-if="slideShow">
        <div class="slider-box">
          <el-slider
            v-model="sliderData"
            :min="2019"
            :max="2024"
            :marks="marks"
            @change="updateHeatmapData($event)"
            :show-tooltip="false"
          />
        </div>
        <div class="control-box">
          <div class="btn" @click="changePlayState(true)" v-if="!playState">
            开始
          </div>
          <div class="btn" @click="changePlayState(false)" v-else>暂停</div>
        </div>
      </div>
    </div>

    <script type="text/javascript">
      const { createApp, computed, ref, reactive, watch } = Vue
      // 滑动条显隐
      const slideShow = ref(false)
      // 滑动条数值
      const sliderData = ref(2019)
      // 滑动条标记
      const marks = reactive({})
      // 滑动条按钮
      const playState = ref(false)
      // 最大滑动条数
      const maxHeatValue = 2024

      // 热力数据
      const normalHeatMapData = {}
      // 热力参数
      const normalHeatMapOptions = {
        bbox: [6063, 5730, 2, 8500, 7006, 80],
        range: [0, 2000]
      }
      // 构造热力数据
      const getData = () => {
        const coordinates = []

        for (let year = 2019; year <= 2024; year++) {
          marks[year] = `${year}年`
          normalHeatMapData[year] = []

          for (let i = 0; i < 200; i++) {
            if (year === 2019) {
              let x = getRandNumBetween(
                normalHeatMapOptions.bbox[0],
                normalHeatMapOptions.bbox[3]
              ) //minX ~ maxX
              let y = getRandNumBetween(
                normalHeatMapOptions.bbox[1],
                normalHeatMapOptions.bbox[4]
              ) //minY ~ maxY
              coordinates.push([x, y, 0])
            }
            normalHeatMapData[year].push({
              id: i.toString(),
              coordinate: coordinates[i], //热力点的坐标
              radius: 200 + Math.random() * 50, //热力点影像半径范围
              heatValue: 2.5 * (year - 2019 + 1) //热力值
            })
          }
        }
      }

      /**
       * 按钮点击事件
       */
      const HeatMapClick = async command => {
        slideShow.value = false
        switch (command) {
          case 'normal':
            addNormalHeatMap()
            break
          case 'customColor':
            addCustomColorHeatMap()
            break
          case 'customerStyle':
            addCustomerStyleHeatMap()
            break

          default:
            break
        }
      }
      /**
       * 添加标准热力图
       */
      const addNormalHeatMap = async () => {
        await fdapi.heatmap.clear()
        __g.camera.set([
          7322.690938, 5211.370625, 1689.738594, -59.478836, -89.046944, 1
        ])
        slideShow.value = true
        await fdapi.heatmap.add(
          'heatmap1',
          normalHeatMapOptions.bbox,
          normalHeatMapOptions.range,
          normalHeatMapData[sliderData.value]
        )
      }

      /**
       * 更新热力值数据
       */
      const updateHeatmapData = year => {
        fdapi.heatmap.update(
          'heatmap1',
          null,
          null,
          normalHeatMapData[year],
          null,
          null,
          null,
          null,
          null,
          null,
          null,
          null,
          null,
          0.2
        ) // 更新热力图
      }

      /**
       * 动态热力按钮状态
       */
      // 定时器
      let timer = null
      const changePlayState = val => {
        playState.value = val
        if (val) {
          // 开始状态，启动定时器
          if (!timer) {
            // 确保定时器未设置
            timer = setInterval(() => {
              sliderData.value = Math.min(sliderData.value + 1, 2024) // 限制最大值
              updateHeatmapData(sliderData.value) // 更新热力图数据
              if (sliderData.value === maxHeatValue) {
                clearInterval(timer)
              }
            }, 500)
          }
        } else {
          // 停止状态，清理定时器
          clearInterval(timer)
          timer = null // 重置定时器
          if (sliderData.value === maxHeatValue) {
            // 如果达到最大值，更新为默认值
            sliderData.value = 2019 // 重置滑块
            addNormalHeatMap()
          }
        }
      }

      /**
       * 添加自定义热力图
       */
      const addCustomColorHeatMap = async () => {
        __g.camera.set([
          8248.564453, 4806.720938, 1022.122578, -36.193855, -108.303246, 1
        ])
        await fdapi.heatmap.clear()
        let bbox1 = [6063.4800000000005, 5730.00125, 1, 8917.72, 6506.29125, 90]
        let range1 = [0, 1]
        let data1 = []
        for (let i = 0; i < 200; i++) {
          let x = getRandNumBetween(bbox1[0], bbox1[3]) //minX ~ maxX
          let y = getRandNumBetween(bbox1[1], bbox1[4]) //minY ~ maxY
          data1.push({
            id: i.toString(),
            coordinate: [x, y, 0], //热力点的坐标
            radius: Math.random() * 200, //热力点影像半径范围
            heatValue: Math.random() //热力值
          })
        }

        let style = 0 // HeatMapStyle.CustomColor自定义颜色热力图
        let textureSize = 1024 // 纹理清晰度，[128~4096];值越大纹理越清晰,创建越耗时
        let opacityMode = 1 // 不透明度模式，0：使用自定义色卡颜色的不透明度 1：使用热力点的不透明度
        let opacityRange = [0, 1] // 不透明度范围，[0~1.0]，仅opacityMode为1时有效
        let blur = 0.85 // 热力点模糊因子，模糊系数越高，渐变越平滑，[0~1.0]
        let colors = {
          gradient: true, // 是否渐变
          invalidColor: [0, 0, 0, 1], // 无效像素点的颜色
          // 每一个对象包含热力值和对应颜色值
          colorStops: [
            {
              value: 0,
              color: [0, 0.968627, 0, 1]
            },
            {
              value: 0.25,
              color: [0.709804, 0.968627, 0, 1]
            },
            {
              value: 0.5,
              color: [1, 0.709804, 0, 1]
            },
            {
              value: 0.75,
              color: [0.868627, 0, 0, 1]
            },
            {
              value: 1,
              color: [1, 0, 0, 1]
            }
          ]
        }
        console.log(data1)
        await fdapi.heatmap.add(
          'heatmap2',
          bbox1,
          range1,
          data1,
          style,
          textureSize,
          opacityMode,
          opacityRange,
          blur,
          colors
        )
        // await fdapi.heatmap.add('heatmap2', bbox1, range1, data1, style, textureSize, opacityMode, opacityRange, blur, colors)
      }

      /**
       * 添加波峰波谷热力图
       */
      const addCustomerStyleHeatMap = async () => {
        __g.camera.set([
          11338.80125, 5116.063203, 979.033047, -17.143091, -178.977509, 1
        ])
        await fdapi.heatmap.clear()
        let bbox2 = [
          6618.470703125, 3644.55029296875, -2.2715864181518555,
          10130.501953125, 6931.4296875, 200.417006969451904
        ]
        let range2 = [0, 10]
        let data2 = []
        for (let i = 0; i < 1100; i++) {
          let x = getRandNumBetween(bbox2[0], bbox2[3]) //minX ~ maxX
          let y = getRandNumBetween(bbox2[1], bbox2[4]) //minY ~ maxY
          data2.push({
            id: i.toString(),
            coordinate: [x, y, 0], //热力点的坐标
            radius: Math.random() * 250, //热力点影像半径范围
            heatValue: 1.5 //热力值
          })
        }

        let style2 = 1 // 波峰波谷热力图,CustomWave
        let textureSize2 = 1024
        let opacityMode2 = 0
        let opacityRange2 = [0, 1]
        let blur2 = 0.85
        let colors2 = {
          gradient: true,
          invalidColor: [0, 0, 0, 1],
          colorStops: [
            {
              value: 0,
              color: [0, 0.968627, 0, 1]
            },
            {
              value: 2.5,
              color: [0.709804, 0.968627, 0, 1]
            },
            {
              value: 5,
              color: [1, 0.709804, 0, 1]
            },
            {
              value: 7.5,
              color: [0.868627, 0, 0, 0.2]
            },
            {
              value: 10,
              //调整色卡的透明度
              color: [1, 0, 0, 0.2]
            }
          ]
        }
        await fdapi.heatmap.add(
          'heatmap3',
          bbox2,
          range2,
          data2,
          style2,
          textureSize2,
          opacityMode2,
          opacityRange2,
          blur2,
          colors2
        )
      }

      /**
       * 防抖
       * @param func setTimeout回调
       * @param wait setTimeout时间
       * @returns {(function(): void)|*}
       */
      const debounce = (func, wait) => {
        let timeout = null
        return function () {
          clearTimeout(timeout)
          timeout = setTimeout(() => {
            func()
          }, wait)
        }
      }
      watch(sliderData.value, debounce(updateHeatmapData, 100), { deep: true })

      /**
       * 生成一个随机数temp=[min，max]
       */
      const getRandNumBetween = (min, max) => {
        return Math.round((Math.random() * (max - min) + min) * 10) / 10
      }

      /**
       * 初始化场景
       */
      const OnLoad = () => {
        const __DigitalTwinPlayer = new DigitalTwinPlayer(HostConfig.Player, {
          domId: 'player',
          apiOptions: {
            onReady: function () {
              fdapi.reset(1 | 2 | 4)

              __g.camera.set([
                10597.256875, 4906.293281, 927.184062, -16.776091, -164.798843,
                1
              ])
            }
          }
        })
      }

      /**
       * 自适应分辨率
       */
      const onResize = async () => {
        let playerView = document.getElementById('player')
        playerView.style.height = window.innerHeight + 'px'
        playerView.style.width = window.innerWidth + 'px'
      }

      const app = createApp({
        setup() {
          // 页面加载调用
          window.addEventListener('load', OnLoad, true)
          // 页面窗口变换调用
          window.addEventListener('resize', onResize, true)

          getData()
          return {
            HeatMapClick,
            sliderData,
            marks,
            changePlayState,
            updateHeatmapData,
            playState,
            slideShow
          }
        }
      })
      app.use(ElementPlus).mount('#dom')

      /**
       * 页面离开事件(离开时清除此页面的操作及重置场景)
       */
      window.onunload = function (e) {
        // 重置场景
        fdapi.reset(1 | 2 | 4)
      }
    </script>
  </body>
</html>
